/*!
 * \file UDPCaster.h
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief UDP广播器头文件
 * 
 * \details 本文件定义了WonderTrader数据服务系统的UDP广播器类UDPCaster：
 *          - 提供UDP协议的实时数据广播功能
 *          - 支持多种数据格式广播（原始数据、JSON格式、扁平格式）
 *          - 支持广播和组播两种传输模式
 *          - 支持tick数据、Level2数据（订单队列、订单明细、逐笔成交）广播
 *          - 基于boost::asio异步网络框架
 *          - 支持多接收端管理和配置
 *          - 提供异步数据发送和接收处理
 *          - 支持网络状态监控和错误处理
 */
#pragma once

#include "../Includes/WTSMarcos.h"
#include "../Includes/WTSObject.hpp"
#include "../Share/StdUtils.hpp"

#include <boost/asio.hpp>
#include <queue>

NS_WTP_BEGIN
	class WTSTickData;
	class WTSQueue;
	class WTSVariant;
	class WTSOrdDtlData;
	class WTSOrdQueData;
	class WTSTransData;
NS_WTP_END

USING_NS_WTP;
class WTSBaseDataMgr;
class DataManager;

/**
 * @class UDPCaster
 * @brief UDP广播器类
 * 
 * @details UDPCaster是WonderTrader数据服务系统的UDP广播器，负责：
 *          - 实现UDP协议的实时数据广播功能
 *          - 支持多种数据格式的广播传输
 *          - 管理广播和组播接收端列表
 *          - 处理tick数据、Level2数据的实时分发
 *          - 基于boost::asio提供异步网络处理
 *          - 支持多线程数据发送和接收
 *          - 提供网络连接状态监控
 *          - 支持数据队列管理和流控
 *          - 集成基础数据管理器和数据管理器
 * 
 * @note 该类是数据分发系统的核心组件，负责实时数据的网络传输
 * @warning 需要正确配置网络参数和接收端信息才能正常工作
 */
class UDPCaster
{
public:
	/**
	 * @brief 构造函数
	 * @details 初始化UDP广播器，设置默认参数
	 */
	UDPCaster();
	
	/**
	 * @brief 析构函数
	 * @details 清理资源，释放网络连接和线程
	 */
	~UDPCaster();

	typedef boost::asio::ip::udp::endpoint EndPoint;
	
	/**
	 * @struct tagUDPReceiver
	 * @brief UDP接收端结构体
	 * @details 定义UDP接收端的网络地址和数据类型信息
	 */
	typedef struct tagUDPReceiver
	{
		EndPoint	_ep;	/*< 网络端点 */
		uint32_t	_type;	/*< 数据类型 */

		/**
		 * @brief 构造函数
		 * @param ep 网络端点
		 * @param t 数据类型
		 */
		tagUDPReceiver(EndPoint ep, uint32_t t)
		{
			_ep = ep;
			_type = t;
		}

	} UDPReceiver;
	typedef std::shared_ptr<UDPReceiver>	UDPReceiverPtr;		/*< UDP接收端智能指针类型 */
	typedef std::vector<UDPReceiverPtr>		ReceiverList;		/*< 接收端列表类型 */

private:
	/**
	 * @brief 处理广播发送完成
	 * @details 处理广播数据发送完成的回调
	 * @param ep 目标端点
	 * @param error 错误代码
	 * @param bytes_transferred 传输字节数
	 */
	void handle_send_broad(const EndPoint& ep, const boost::system::error_code& error, std::size_t bytes_transferred); 
	
	/**
	 * @brief 处理组播发送完成
	 * @details 处理组播数据发送完成的回调
	 * @param ep 目标端点
	 * @param error 错误代码
	 * @param bytes_transferred 传输字节数
	 */
	void handle_send_multi(const EndPoint& ep, const boost::system::error_code& error, std::size_t bytes_transferred); 

	/**
	 * @brief 执行数据接收
	 * @details 异步接收网络数据
	 */
	void do_receive();
	
	/**
	 * @brief 执行数据发送
	 * @details 异步发送网络数据
	 */
	void do_send();

	/**
	 * @brief 广播数据对象
	 * @details 广播指定类型的数据对象
	 * @param data 数据对象
	 * @param dataType 数据类型
	 */
	void broadcast(WTSObject* data, uint32_t dataType);

public:
	/**
	 * @brief 初始化UDP广播器
	 * @details 根据配置参数初始化UDP广播器
	 * @param cfg 配置参数对象
	 * @param bdMgr 基础数据管理器
	 * @param dtMgr 数据管理器
	 * @return bool 初始化是否成功
	 */
	bool	init(WTSVariant* cfg, WTSBaseDataMgr* bdMgr, DataManager* dtMgr);
	
	/**
	 * @brief 启动UDP广播器
	 * @details 启动UDP广播服务，开始监听指定端口
	 * @param bport 绑定端口
	 */
	void	start(int bport);
	
	/**
	 * @brief 停止UDP广播器
	 * @details 停止UDP广播服务，关闭网络连接
	 */
	void	stop();

	/**
	 * @brief 添加广播接收端
	 * @details 添加一个广播模式的数据接收端
	 * @param remote 远程地址
	 * @param port 端口号
	 * @param type 数据类型（默认为0）
	 * @return bool 添加是否成功
	 */
	bool	addBRecver(const char* remote, int port, int type = 0);
	
	/**
	 * @brief 添加组播接收端
	 * @details 添加一个组播模式的数据接收端
	 * @param remote 远程地址
	 * @param port 端口号
	 * @param sendport 发送端口
	 * @param type 数据类型（默认为0）
	 * @return bool 添加是否成功
	 */
	bool	addMRecver(const char* remote, int port, int sendport, int type = 0);

	/**
	 * @brief 广播tick数据
	 * @details 广播实时tick行情数据
	 * @param curTick 当前tick数据
	 */
	void	broadcast(WTSTickData* curTick);
	
	/**
	 * @brief 广播订单队列数据
	 * @details 广播Level2订单队列数据
	 * @param curOrdQue 当前订单队列数据
	 */
	void	broadcast(WTSOrdQueData* curOrdQue);
	
	/**
	 * @brief 广播订单明细数据
	 * @details 广播Level2订单明细数据
	 * @param curOrdDtl 当前订单明细数据
	 */
	void	broadcast(WTSOrdDtlData* curOrdDtl);
	
	/**
	 * @brief 广播逐笔成交数据
	 * @details 广播Level2逐笔成交数据
	 * @param curTrans 当前逐笔成交数据
	 */
	void	broadcast(WTSTransData* curTrans);

private:
	typedef boost::asio::ip::udp::socket	UDPSocket;		/*< UDP套接字类型 */
	typedef std::shared_ptr<UDPSocket>		UDPSocketPtr;	/*< UDP套接字智能指针类型 */

	enum 
	{ 
		max_length = 2048 	/*< 最大数据长度 */
	};

	boost::asio::ip::udp::endpoint	m_senderEP;		/*< 发送端网络端点 */
	char			m_data[max_length];				/*< 数据缓冲区 */

	//广播接收端列表
	ReceiverList	m_listFlatRecver;	/*< 扁平格式广播接收端列表 */
	ReceiverList	m_listJsonRecver;	/*< JSON格式广播接收端列表 */
	ReceiverList	m_listRawRecver;	/*< 原始格式广播接收端列表 */
	UDPSocketPtr	m_sktBroadcast;		/*< 广播套接字 */
	UDPSocketPtr	m_sktSubscribe;		/*< 订阅套接字 */

	typedef std::pair<UDPSocketPtr,UDPReceiverPtr>	MulticastPair;	/*< 组播对类型 */
	typedef std::vector<MulticastPair>	MulticastList;				/*< 组播列表类型 */
	MulticastList	m_listFlatGroup;	/*< 扁平格式组播列表 */
	MulticastList	m_listJsonGroup;	/*< JSON格式组播列表 */
	MulticastList	m_listRawGroup;		/*< 原始格式组播列表 */
	boost::asio::io_context		m_ioservice;	/*< 异步IO服务 */
	StdThreadPtr	m_thrdIO;					/*< IO线程 */

	StdThreadPtr	m_thrdCast;		/*< 广播线程 */
	StdCondVariable	m_condCast;		/*< 广播条件变量 */
	StdUniqueMutex	m_mtxCast;		/*< 广播互斥锁 */
	bool			m_bTerminated;	/*< 终止标志 */

	WTSBaseDataMgr*	m_bdMgr;	/*< 基础数据管理器 */
	DataManager*	m_dtMgr;	/*< 数据管理器 */

	/**
	 * @struct _CastData
	 * @brief 广播数据结构体
	 * @details 封装待广播的数据对象和类型信息
	 */
	typedef struct _CastData
	{
		uint32_t	_datatype;	/*< 数据类型 */
		WTSObject*	_data;		/*< 数据对象 */

		/**
		 * @brief 构造函数
		 * @param obj 数据对象（默认为NULL）
		 * @param dataType 数据类型（默认为0）
		 */
		_CastData(WTSObject* obj = NULL, uint32_t dataType = 0)
			: _data(obj), _datatype(dataType)
		{
			if (_data)
				_data->retain();
		}

		/**
		 * @brief 拷贝构造函数
		 * @param data 源数据对象
		 */
		_CastData(const _CastData& data)
			: _data(data._data), _datatype(data._datatype)
		{
			if (_data)
				_data->retain();
		}

		/**
		 * @brief 析构函数
		 * @details 释放数据对象引用
		 */
		~_CastData()
		{
			if (_data)
			{
				_data->release();
				_data = NULL;
			}
		}
	} CastData;

	std::queue<CastData>		m_dataQue;	/*< 数据队列 */
};